--[[
	Ikarus Unit-Frames Addon	
	released under GNU General Public License version 3 (GPLv3) 
	by McGaerty & Sl4ker
	
	contact: mcgaerty@ikarus-systems.net rom@sl4ker.de	
	download: http://rom.curse.com/downloads/rom-addons/details/ikarus-unitframes.aspx
	
	special thanks to Qwox and novayuna for inspiration and stable basics
]]



local ikarus = _G["ikarus"];
--  Lists all delegate classes
ikarus.delegates = {};


--[[
     ***********************************************************************
    BEGIN UNIT DELEGATES
     ***********************************************************************
]]


--  ***********************************************************************
--  abstract base class for handler classes
ikarus.delegates.BasicUnitDelegateClass = ikarus:NewClass(nil);

--[[
	Required functions for subclasses:
		-ShowDefaultFrame		registers all events for default frame and shows it
		-HideDefaultFrame		unregisters all events for default frame and hides it
]]

function ikarus.delegates.BasicUnitDelegateClass:Init()
end;

function ikarus.delegates.BasicUnitDelegateClass:SetEnabled(enabled, forceUpdate)
	--  Changed for reasons of readability
	if(self.enabled ~= nil and enabled ~= self.enabled) then
		forceUpdate = true;
	end;
	self.enabled = enabled;
	if(forceUpdate) then
		self:UpdateAll();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:IsEnabled()
	return self.enabled == true;
end;

function ikarus.delegates.BasicUnitDelegateClass:SetDummy(dummy)
	if(dummy ~= self.dummy) then
		self.dummy = dummy;
		self:UpdateAll();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:IsDummy()
	return self.dummy == true;
end;

function ikarus.delegates.BasicUnitDelegateClass:GetFrame()
	return self.frame;
end;

function ikarus.delegates.BasicUnitDelegateClass:RegisterEvent(event, unit)
	ikarus:RegisterEvent(tostring(event), tostring(unit));
end;

function ikarus.delegates.BasicUnitDelegateClass:UnregisterEvent(event, unit)
	ikarus:UnregisterEvent(tostring(event), tostring(unit));
end;

function ikarus.delegates.BasicUnitDelegateClass:UnregisterEvents(delegate)
	if(delegate.eventList) then
		local unit = delegate:Unit();
		for event,_ in pairs(delegate.eventList) do
			self:UnregisterEvent(tostring(event), unit);
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:RegisterEvents(delegate)
	if(delegate.eventList) then
		local unit = delegate:Unit();
		for event,_ in pairs(delegate.eventList) do
			self:RegisterEvent(tostring(event), unit);
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:GetProperty(property)
	return self:Profile().GENERAL[property];
end;

function ikarus.delegates.BasicUnitDelegateClass:Profile()
	return ikarus.profile[self.unit];
end;

function ikarus.delegates.BasicUnitDelegateClass:Unit()
	return self.unit;
end;

function ikarus.delegates.BasicUnitDelegateClass:IsUnit()
	return true;
end;

--  Used by proxy delegates like party and raid
function ikarus.delegates.BasicUnitDelegateClass:SubUnit()
	return self.unit;
end;

function ikarus.delegates.BasicUnitDelegateClass:LoadConfig(delegate) 
	local config = delegate:Profile();
	if(config == nil) then
		ikarus.debug:Print(delegate.unit);
	end;
	
	if not (config.GENERAL.PROXY) then
		if(config.GENERAL.VISIBLE) then
			self:RegisterEvents(delegate);
		else
			self:UnregisterEvents(delegate);
		end;
	end;
	
	--  Hide default frame or show it
	if(not config.GENERAL.VISIBLE and config.GENERAL.USE_DEFAULT_FRAME) then
		delegate:ShowDefaultFrame();
	else
		delegate:HideDefaultFrame();
	end;
	
	--  Bars
	if(config.HEALTHBAR.VISIBLE) then
		self:LoadBarConfig(config.HEALTHBAR);
	end;
	if(config.MANABAR.VISIBLE) then
		self:LoadBarConfig(config.MANABAR);
	end;
	if(config.SKILLBAR.VISIBLE) then
		self:LoadBarConfig(config.SKILLBAR);
	end;
	
	--  Labels
	--[[local font = tostring(ikarus.constants.ADDON_DIR .. "fonts/")
	if(config.LABELS.TOPTEXT_VISIBLE) then
		getglobal(config.LABELS.TOPTEXT_FRAME):SetFont(font..tostring(config.LABELS.TOPTEXT_FONT));
	end;
	if(config.LABELS.RIGHTTEXT_VISIBLE) then
		getglobal(config.LABELS.RIGHTTEXT_FRAME):SetFont(font..tostring(config.LABELS.RIGHTTEXT_FONT));
	end;
	if(config.LABELS.BOTTOMTEXT_VISIBLE) then
		getglobal(config.LABELS.BOTTOMTEXT_FRAME):SetFont(font..tostring(config.LABELS.BOTTOMTEXT_FONT));
	end;
	if(config.LABELS.LEFTTEXT_VISIBLE) then
		getglobal(config.LABELS.LEFTTEXT_FRAME):SetFont(font..tostring(config.LABELS.LEFTTEXT_FONT));
	end;
	]]
end;

function ikarus.delegates.BasicUnitDelegateClass:LoadBarConfig(config)
	local tex = tostring(config.TEXTURE);
	local delegate = ikarus:GetDelegate("global");
	if(delegate:Profile().GENERAL.USE_GLOBAL_TEXTURE) then
		tex = tostring(delegate:Profile().GENERAL.GLOBAL_TEXTURE);
	end;
	local path = tostring(ikarus.constants.ADDON_DIR .. "graphics/statusbar/"..tex)
	--  Background
	local frame = getglobal(config.FRAME.."BackgroundTexture");
	--local color = config.BACKGROUND_COLOR;
	frame:SetTexture(path);
    --frame:SetColor(color.r, color.g, color.b);
	--  Foreground
	frame = getglobal(config.FRAME.."ForegroundTexture");
	--color = config.FOREGROUND_COLOR;
	frame:SetTexture(path);
    --frame:SetColor(color.r, color.g, color.b);
	
	--[[local font = tostring(ikarus.constants.ADDON_DIR .. "fonts/")
	
	frame = getglobal(config.FRAME);
    getglobal(frame:GetName().."LeftText"):SetFont(font..tostring(config.LEFTTEXT_FONT));
    getglobal(frame:GetName().."RightText"):SetFont(font..tostring(config.RIGHTTEXT_FONT));
    getglobal(frame:GetName().."OutsideLeftText"):SetFont(font..tostring(config.OUTSIDE_LEFTTEXT_FONT));
    getglobal(frame:GetName().."OutsideRightText"):SetFont(font..tostring(config.OUTSIDE_RIGHTTEXT_FONT));
	]]
end;

function ikarus.delegates.BasicUnitDelegateClass:LoadBoundProperties(delegate)
	local config = delegate:Profile();
	
	if (config.GENERAL.VISIBLE) then
		local scale = GetUIScale() * tonumber(config.GENERAL.SCALE);
		
		local frame = getglobal(config.GENERAL.FRAME);
		frame.mainUnit = delegate:Unit();
		frame.unit = delegate:SubUnit();
		local sum, height, width = 0, tonumber(config.GENERAL.HEIGHT), tonumber(config.GENERAL.WIDTH);
		
		if(config.DOCKING and config.DOCKING.ENABLE) then
			local target = ikarus.profile[string.lower(config.DOCKING.TARGET)].GENERAL.FRAME;
			ikarus.profile[delegate.unit].GENERAL.FRAME_LOCKED = true;
			ikarus.ui:SetAlignment(frame, target, config.DOCKING.ALIGNMENT, config.DOCKING.OFFSET_X, config.DOCKING.OFFSET_Y, GetUIScale());
		elseif not(config.GENERAL.PROXY == true) then
			ikarus.ui:SetAnchor(frame:GetName(), "UIParent", "TOPLEFT", "TOPLEFT", config.GENERAL.OFFSET_X, config.GENERAL.OFFSET_Y, GetUIScale());
		end;
		ikarus.ui:Resize(frame, width, height, scale);
		frame:SetAlpha(tonumber(config.GENERAL.ALPHA));		
		
		if(config.HEALTHBAR.VISIBLE) then sum = sum + tonumber(config.HEALTHBAR.WEIGHT); end;
		if(config.MANABAR.VISIBLE) then sum = sum + tonumber(config.MANABAR.WEIGHT); end;
		if(config.SKILLBAR.VISIBLE) then sum = sum + tonumber(config.SKILLBAR.WEIGHT); end;
				
		--  Healthbar
		self:LoadBarBoundProperties(config.HEALTHBAR, delegate, width,
			math.floor(height * tonumber(config.HEALTHBAR.WEIGHT) / sum), scale);
		--  Manabar
		self:LoadBarBoundProperties(config.MANABAR, delegate, width,
			math.floor(height * tonumber(config.MANABAR.WEIGHT) / sum), scale);
		--  Skillbar
		self:LoadBarBoundProperties(config.SKILLBAR, delegate, width,
			math.floor(height * tonumber(config.SKILLBAR.WEIGHT) / sum), scale);
					
		--  Portrait
		self:LoadSubFrameProperties(config.PORTRAIT, config.GENERAL.FRAME, nil, scale);
		
		--  Raid target
		self:LoadSubFrameProperties(config.ICONS, config.GENERAL.FRAME, "RAIDTARGET", scale);
		
		--  Boss
		self:LoadSubFrameProperties(config.ICONS, config.GENERAL.FRAME, "BOSS", scale);
		
		--  Raid leader
		self:LoadSubFrameProperties(config.ICONS, config.GENERAL.FRAME, "RAIDLEADER", scale);
		
		--  Loot master
		self:LoadSubFrameProperties(config.ICONS, config.GENERAL.FRAME, "LOOTMASTER", scale);
		
		--  PVP state
		self:LoadSubFrameProperties(config.ICONS, config.GENERAL.FRAME, "PVPSTATE", scale);
		
		--  Main Class
		self:LoadSubFrameProperties(config.ICONS, config.GENERAL.FRAME, "MAINCLASS", scale);
		
		--  Sub Class
		self:LoadSubFrameProperties(config.ICONS, config.GENERAL.FRAME, "SUBCLASS", scale);
		
		--  Buffs
		self:LoadBuffBoundProperties(config.BUFFS, delegate, "BUFFS", scale);
		
		--  Debuffs
		self:LoadBuffBoundProperties(config.BUFFS, delegate, "DEBUFFS", scale);
		
		--  Labels
		self:LoadTextBoundProperties(config.LABELS, frame, "TOPTEXT", width, 25, scale);
		ikarus.ui:SetAnchor(config.LABELS.TOPTEXT_FRAME, frame, "BOTTOMLEFT", "TOPLEFT", config.LABELS.TOPTEXT_OFFSET_X, config.LABELS.TOPTEXT_OFFSET_Y);
		
		self:LoadTextBoundProperties(config.LABELS, frame, "RIGHTTEXT", width, 25, scale);
		ikarus.ui:SetAnchor(config.LABELS.RIGHTTEXT_FRAME, frame, "TOPLEFT", "TOPRIGHT", config.LABELS.RIGHTTEXT_OFFSET_X, config.LABELS.RIGHTTEXT_OFFSET_Y);
		
		self:LoadTextBoundProperties(config.LABELS, frame, "BOTTOMTEXT", width, 25, scale);
		ikarus.ui:SetAnchor(config.LABELS.BOTTOMTEXT_FRAME, frame, "TOPLEFT", "BOTTOMLEFT", config.LABELS.BOTTOMTEXT_OFFSET_X, config.LABELS.BOTTOMTEXT_OFFSET_Y);
		
		self:LoadTextBoundProperties(config.LABELS, frame, "LEFTTEXT", width, 25, scale);
		ikarus.ui:SetAnchor(config.LABELS.LEFTTEXT_FRAME, frame, "TOPRIGHT", "TOPLEFT", config.LABELS.LEFTTEXT_OFFSET_X, config.LABELS.LEFTTEXT_OFFSET_Y);
						
		frame:Show();
	else
		getglobal(config.GENERAL.FRAME):Hide();
	end;	
end;

function ikarus.delegates.BasicUnitDelegateClass:LoadBarBoundProperties(config, delegate, width, height, scale)
	if(config.VISIBLE) then
		--  Background
		local frame = getglobal(config.FRAME.."BackgroundTexture");
		ikarus.ui:Resize(frame, width, height, scale);
	    frame:SetColor(unpackCol(config.BACKGROUND_COLOR));
		frame:SetAlpha(config.BACKGROUND_COLOR.a or 1);
		--  Foreground
		frame = getglobal(config.FRAME.."ForegroundTexture");
		ikarus.ui:Resize(frame, width, height, scale);
		local color;
		if(config.COLORIZER and config.COLORIZER ~= "NONE") then
			color = ikarus.colorizers:Colorize(config.COLORIZER, delegate);
		end;
		if(color == nil) then
			color = config.FOREGROUND_COLOR;
		end;
	    frame:SetColor(unpackCol(color));
		frame:SetAlpha(color.a or 1);
		
		frame = getglobal(config.FRAME);
		ikarus.ui:Resize(frame, width, height, scale);
		--  Configure left text
		self:LoadTextBoundProperties(config, frame, "LEFTTEXT", width, height, scale);
		ikarus.ui:SetAnchor(config.LEFTTEXT_FRAME, frame, "LEFT", "LEFT", config.LEFTTEXT_OFFSET_X, 0, scale);
		--  Configure right text
		self:LoadTextBoundProperties(config, frame, "RIGHTTEXT", width, height, scale);
		ikarus.ui:SetAnchor(config.RIGHTTEXT_FRAME, frame, "RIGHT", "RIGHT", config.RIGHTTEXT_OFFSET_X, 0, scale);
		--  Configure outside left text
		self:LoadTextBoundProperties(config, frame, "OUTSIDE_LEFTTEXT", 50, height, scale);
		ikarus.ui:SetAnchor(config.OUTSIDE_LEFTTEXT_FRAME, frame, "RIGHT", "LEFT", config.OUTSIDE_LEFTTEXT_OFFSET_X, 0, scale);
		--  Configure outside right text
		self:LoadTextBoundProperties(config, frame, "OUTSIDE_RIGHTTEXT", 50, height, scale);
		ikarus.ui:SetAnchor(config.OUTSIDE_RIGHTTEXT_FRAME, frame, "LEFT", "RIGHT", config.OUTSIDE_RIGHTTEXT_OFFSET_X, 0, scale);
		frame:Show();
	else
		local frame = getglobal(config.FRAME);
		ikarus.ui:Resize(frame, width, 0);
		frame:Hide();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:LoadBuffBoundProperties(config, delegate, prefix, scale)
	if(ikarus.utils:IsValidString(prefix)) then
		prefix = prefix.."_";
	else
		prefix = "";
	end;
	if(config[prefix.."FRAME"]) then
		local frame = getglobal(config[prefix.."FRAME"]);
		if(config[prefix.."VISIBLE"]) then		
			scale = scale * tonumber(config[prefix.."SCALE"]);
			local index, width, height;
			local spacing, cols = tonumber(config[prefix.."SPACING"]), tonumber(config[prefix.."COLUMNS"]);
			local rows = math.ceil(20 / cols);
			for i = 0,rows-1 do
				for j= 1,cols do
					index = i * cols + j;
					if(index <= 20) then
						frame = getglobal(config[prefix.."FRAME"].."Buff"..index);
						
						frame.mainUnit = delegate:Unit();
						frame.unit = delegate:SubUnit();
						frame.buff = ("BUFFS_" == prefix);
						frame.debuff = not frame.buff;
						frame:SetID(index);
						
						getglobal(frame:GetName().."Count"):SetFontSize(config[prefix.."FONTSIZE"]);
						getglobal(frame:GetName().."Count"):SetText("");

						getglobal(frame:GetName().."Duration"):SetFontSize(config[prefix.."FONTSIZE"]);
						getglobal(frame:GetName().."Duration"):SetText("");
						ikarus.ui:Resize(frame, 18, 18, scale);
						if(index == 1) then
							ikarus.ui:SetAnchor(frame, config[prefix.."FRAME"], "TOPLEFT", "TOPLEFT", 0, 0);
						elseif(j == 1) then
							ikarus.ui:SetAnchor(frame, config[prefix.."FRAME"].."Buff"..(i*cols+j-cols), "TOPLEFT", "BOTTOMLEFT", 0, spacing);
						else
							ikarus.ui:SetAnchor(frame, config[prefix.."FRAME"].."Buff"..(index - 1), "TOPLEFT", "TOPRIGHT", spacing, 0);
						end;
					end;
				end;
			end;
			frame = getglobal(config[prefix.."FRAME"]);
			width = cols * 18 + (cols - 1) * spacing;
			height = rows * 18 + (rows - 1) * spacing;
			ikarus.ui:Resize(frame, width, height, scale);
			ikarus.ui:SetAlignment(frame, delegate:Profile().GENERAL.FRAME, config[prefix.."ALIGNMENT"], config[prefix.."OFFSET_X"], config[prefix.."OFFSET_Y"]);
			frame:Show();
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:LoadSubFrameProperties(config, parent, prefix, scale)
	if(ikarus.utils:IsValidString(prefix)) then
		prefix = prefix.."_";
	else
		prefix = "";
	end;
	if(config[prefix.."FRAME"]) then
		local frame = getglobal(config[prefix.."FRAME"]);
		if(config[prefix.."VISIBLE"]) then
			ikarus.ui:SetAlignment(frame, parent, config[prefix.."ALIGNMENT"], 
				config[prefix.."OFFSET_X"], config[prefix.."OFFSET_Y"]);
			if(config[prefix.."WIDTH"] and config[prefix.."HEIGHT"]) then
				scale = scale * tonumber(config[prefix.."SCALE"]);
				ikarus.ui:Resize(frame, config[prefix.."WIDTH"] * scale, config[prefix.."HEIGHT"] * scale);
			end;
			frame:Show();
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:LoadTextBoundProperties(config, parent, prefix, width, height, scale)
	if(ikarus.utils:IsValidString(prefix)) then
		prefix = prefix.."_";
	else
		prefix = "";
	end;
	if(config[prefix.."FRAME"]) then
		local frame = getglobal(config[prefix.."FRAME"]);
		if(config[prefix.."VISIBLE"]) then
			local color = config[prefix.."TEXTCOLOR"];
			frame:SetColor(unpackCol(color));
			ikarus.ui:Resize(frame, width, height, scale);
			--frame:SetHeight(tonumber(config[prefix.."FONTSIZE"]) + 2);
			frame:SetFontSize(tonumber(config[prefix.."FONTSIZE"]));
			frame:SetText("");  --  Workaround for stupid API behavior...
			frame:Show();
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:OnScriptEvent(delegate, event, frame, key, ...)
	--ikarus.debug:Print(delegate.frame:GetName().." "..tostring(event).." "..tostring(key));
    if(event == "OnDragStart")then
        if not (delegate:Profile().GENERAL.FRAME_LOCKED or ikarus.ui:IsLocked()) then
            getglobal(delegate:Profile().GENERAL.FRAME):StartMoving("TOPLEFT");
        end;
    elseif(event == "OnDragStop")then
        if not (delegate:Profile().GENERAL.FRAME_LOCKED or ikarus.ui:IsLocked()) then
			local config = delegate:Profile();
            getglobal(config.GENERAL.FRAME):StopMovingOrSizing();
			local scale = GetUIScale() * tonumber(config.GENERAL.SCALE);
			local x, y = getglobal(config.GENERAL.FRAME):GetPos();
            config.GENERAL.OFFSET_X, config.GENERAL.OFFSET_Y = x / scale, y / scale;
            ikarus.config:SaveProfile();
			delegate:UpdateAll();
        end;
    elseif(event == "OnHide")then
		CloseDropDownMenus();
    elseif(event == "OnBuffClick")then
		if(delegate:Unit() == "player" and key == "RBUTTON" and frame.buff) then
			CancelPlayerBuff(frame:GetID());
		end;
    elseif(event == "OnBuffUpdate")then
		local leftTime;
		if(frame.buff and delegate:Profile().BUFFS.BUFFS_SHOW_DURATION) then
			leftTime = UnitBuffLeftTime(frame.unit, frame:GetID());
		elseif(frame.debuff and delegate:Profile().BUFFS.DEBUFFS_SHOW_DURATION) then
			leftTime = UnitDebuffLeftTime(frame.unit, frame:GetID());
		end;
		if(leftTime) then
			getglobal(frame:GetName().."Duration"):SetText(SecondsToTimeAbbrev(leftTime));
		else
			getglobal(frame:GetName().."Duration"):SetText("");
		end;
    elseif(event == "OnBuffEnter")then
		GameTooltip:SetOwner(frame, "ANCHOR_BOTTOMLEFT");
		if(frame.buff) then
			GameTooltip:SetUnitBuff(frame.unit, frame:GetID());
		else
			GameTooltip:SetUnitDebuff(frame.unit, frame:GetID());
		end;
    elseif(event == "OnBuffLeave")then
		GameTooltip:Hide();
    elseif(event == "OnClick")then	
		if(key == "LBUTTON") then
			if(SpellIsTargeting()) then
				SpellTargetUnit(frame.unit);
			elseif(CursorHasItem()) then
				DropItemOnUnit(frame.unit);
			else
				TargetUnit(frame.unit);
			end;
		end;
    end;
end;


--  Update functions for displayed properties

function ikarus.delegates.BasicUnitDelegateClass:UpdateAll(delegate)
	local frame = getglobal(delegate:Profile().GENERAL.FRAME);
	if(delegate:IsDummy() and delegate:Profile().GENERAL.VISIBLE) then
		local config = delegate:Profile();
		self:ShowDummyBar(config.HEALTHBAR);
		self:ShowDummyBar(config.MANABAR);
		self:ShowDummyBar(config.SKILLBAR);
		self:ShowDummyLabel(config.LABELS, "LEFTTEXT");
		self:ShowDummyLabel(config.LABELS, "RIGHTTEXT");
		self:ShowDummyLabel(config.LABELS, "TOPTEXT");
		self:ShowDummyLabel(config.LABELS, "BOTTOMTEXT");
		self:ShowDummyBuffs(config.BUFFS, "BUFFS", 12);
		self:ShowDummyBuffs(config.BUFFS, "DEBUFFS", 15);
		self:ShowDummyFrame(config.PORTRAIT);
		self:ShowDummyFrame(config.ICONS, "PVPSTATE");
		self:ShowDummyFrame(config.ICONS, "LEADER");
		self:ShowDummyFrame(config.ICONS, "RAIDTARGET");
		self:ShowDummyFrame(config.ICONS, "LOOTER");
		self:ShowDummyFrame(config.ICONS, "BOSS");
		self:ShowDummyFrame(config.ICONS, "MAINCLASS");
		self:ShowDummyFrame(config.ICONS, "SUBCLASS");
		frame:Show();
	elseif(UnitExists(delegate.unit) and delegate:Profile().GENERAL.VISIBLE and delegate:IsEnabled()) then
		self:UpdateBarColors(delegate);
		self:UpdateHealth(delegate);
		self:UpdateMana(delegate);
		self:UpdateSkill(delegate);
		self:UpdateBuffs(delegate);
		self:UpdatePortrait(delegate);
		self:UpdatePVPStateIcon(delegate);
		self:UpdatePartyLeaderIcon(delegate);
		self:UpdateLootMasterIcon(delegate);
		self:UpdateRaidTargetIcon(delegate);
		self:UpdateBossIcon(delegate);
		self:UpdateMainClassIcon(delegate);
		self:UpdateSubClassIcon(delegate);
		self:UpdateText(delegate);
		if not(frame:IsVisible()) then
			frame:Show();
		end;
	else
		if(frame:IsVisible()) then
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateBarColors(delegate)
	if(delegate:Profile().GENERAL.VISIBLE) then
		local colorH, colorM, colorS;
		if(delegate:Profile().GENERAL.WOW_STYLE or ikarus.profile.global.GENERAL.WOW_STYLE) then
			colorH = ikarus.constants.colors.WOW[UnitClassToken(delegate.unit)];
			colorM = ikarus.constants.colors.WOW["MANATYPE"..UnitManaType(delegate.unit)];
			colorS = ikarus.constants.colors.WOW["MANATYPE"..UnitSkillType(delegate.unit)];
		else
			colorH = delegate:Profile().HEALTHBAR.FOREGROUND_COLOR;
			colorM = delegate:Profile().MANABAR.FOREGROUND_COLOR;
			colorS = delegate:Profile().SKILLBAR.FOREGROUND_COLOR;
			if(delegate:Profile().HEALTHBAR.CLASS_COLOR or ikarus.profile.global.GENERAL.SYSTEM_COLOR) then
				colorH = ikarus.constants.colors.CLASS[UnitClassToken(delegate.unit)];
			end;
			if(delegate:Profile().MANABAR.SYSTEM_COLOR or ikarus.profile.global.GENERAL.SYSTEM_COLOR) then
				colorM = SkillBarColor[UnitManaType(delegate.unit)];
			end;
			if(delegate:Profile().SKILLBAR.SYSTEM_COLOR or ikarus.profile.global.GENERAL.SYSTEM_COLOR) then
				colorS = SkillBarColor[UnitSkillType(delegate.unit)];
			end;
		end;
		local frame = getglobal(delegate:Profile().HEALTHBAR.FRAME.."ForegroundTexture");
		frame:SetColor(colorH.r, colorH.g, colorH.b, colorH.a);
		frame = getglobal(delegate:Profile().MANABAR.FRAME.."ForegroundTexture");
		frame:SetColor(colorM.r, colorM.g, colorM.b, colorM.a);
		frame = getglobal(delegate:Profile().SKILLBAR.FRAME.."ForegroundTexture");
		frame:SetColor(colorS.r, colorS.g, colorS.b, colorS.a);
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateText(delegate)
	if(delegate:Profile().GENERAL.VISIBLE) then
		ikarus.mobdb:UpdateMobDB(delegate.unit);
		--  Bars
		self:UpdateBarText(delegate, "HEALTHBAR");
		self:UpdateBarText(delegate, "MANABAR");
		self:UpdateBarText(delegate, "SKILLBAR");
		
		--  Labels
		local config = delegate:Profile();
		self:UpdateLabel(delegate, config.LABELS, "TOPTEXT");
		self:UpdateLabel(delegate, config.LABELS, "RIGHTTEXT");
		self:UpdateLabel(delegate, config.LABELS, "BOTTOMTEXT");
		self:UpdateLabel(delegate, config.LABELS, "LEFTTEXT");
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateLabel(delegate, config, prefix)
	if(ikarus.utils:IsValidString(prefix)) then
		prefix = prefix.."_";
	else
		prefix = "";
	end;
	if(config[prefix.."VISIBLE"]) then
		local color;
		if(config[prefix.."COLORIZER"] and config[prefix.."COLORIZER"] ~= "NONE") then
			color = ikarus.colorizers:Colorize(config[prefix.."COLORIZER"], delegate);
		end;
		if(color == nil) then
			color = config[prefix.."TEXTCOLOR"];
		end;
		local frame = getglobal(config[prefix.."FRAME"]);
		frame:SetColor(unpackCol(color));
		frame:SetText(ikarus.iuc:Process(config[prefix.."CONTENT"], delegate));
		--frame:SetWidth(frame:GetTextWidth() + 5);
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateBarText(delegate, barName)
	if(delegate:Profile()[barName].VISIBLE) then
		local config = delegate:Profile()[barName];
		self:UpdateLabel(delegate, config, "LEFTTEXT");
		self:UpdateLabel(delegate, config, "RIGHTTEXT");
		self:UpdateLabel(delegate, config, "OUTSIDE_LEFTTEXT");
		self:UpdateLabel(delegate, config, "OUTSIDE_RIGHTTEXT");
	end;
end;


function ikarus.delegates.BasicUnitDelegateClass:UpdateHealth(delegate)
	local config = delegate:Profile();
	if(config.GENERAL.VISIBLE and config.HEALTHBAR.VISIBLE) then
		local frame = getglobal(config.HEALTHBAR.FRAME.."ForegroundTexture");
		local width, hp, mhp = getglobal(config.GENERAL.FRAME):GetWidth(), tonumber(UnitHealth(delegate.unit)), tonumber(UnitMaxHealth(delegate.unit));
		if(mhp > 0 and hp > 0) then
			if(config.HEALTHBAR.COLORIZER and config.HEALTHBAR.COLORIZER ~= "NONE") then
				local color = ikarus.colorizers:Colorize(config.HEALTHBAR.COLORIZER, delegate);
				if(color ~= nil) then
					frame:SetColor(unpackCol(color));
				end;
			end;
			frame:Show();
			frame:SetWidth(math.floor(hp / mhp * width));
			frame:SetTexCoord(0, hp/mhp, 0, 1);
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateMana(delegate)
	local config = delegate:Profile();
	if(config.GENERAL.VISIBLE and config.MANABAR.VISIBLE) then
		local frame = getglobal(config.MANABAR.FRAME.."ForegroundTexture");
		local width, mp, mmp = getglobal(config.GENERAL.FRAME):GetWidth(), UnitMana(delegate.unit), UnitMaxMana(delegate.unit);
		if(mmp > 0 and mp > 0) then
			if(config.MANABAR.COLORIZER and config.MANABAR.COLORIZER ~= "NONE") then
				local color = ikarus.colorizers:Colorize(config.MANABAR.COLORIZER, delegate);
				if(color ~= nil) then
					frame:SetColor(unpackCol(color));
				end;
			end;
			frame:Show();
			frame:SetWidth(math.floor(mp / mmp * width));
			frame:SetTexCoord(0, mp/mmp, 0, 1);
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateSkill(delegate)
	local config = delegate:Profile();
	if(config.GENERAL.VISIBLE and config.SKILLBAR.VISIBLE) then
		local frame = getglobal(config.SKILLBAR.FRAME.."ForegroundTexture");
		local width, sp, msp = getglobal(config.GENERAL.FRAME):GetWidth(), UnitSkill(delegate.unit), UnitMaxSkill(delegate.unit);
		if(msp > 0 and sp > 0) then
			if(config.SKILLBAR.COLORIZER and config.SKILLBAR.COLORIZER ~= "NONE") then
				local color = ikarus.colorizers:Colorize(config.SKILLBAR.COLORIZER, delegate);
				if(color ~= nil) then
					frame:SetColor(unpackCol(color));
				end;
			end;
			frame:Show();
			frame:SetWidth(math.floor(sp / msp * width));
			frame:SetTexCoord(0, sp/msp, 0, 1);
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateBuffs(delegate)
	if(delegate:Profile().GENERAL.VISIBLE and delegate:Profile().BUFFS.BUFFS_VISIBLE) then
		--  Display buff buttons
		local frame, name, texture, count;
		for index = 1,20 do
			name, texture, count = UnitBuff(delegate.unit, index);
			frame = getglobal(delegate:Profile().BUFFS.BUFFS_FRAME.."Buff"..index);
			if(name) then
				if(count < 1) then
					count = "";
				end;
				getglobal(frame:GetName().."Icon"):SetTexture(texture);
				getglobal(frame:GetName().."Count"):SetText(count);
				getglobal(frame:GetName().."Duration"):SetText("");
				frame:Show();
			else
				frame:Hide();
			end;
	
			if(GameTooltip:IsOwned(frame)) then
				GameTooltip:SetUnitBuff(delegate.unit, index);
			end;
		end;
	end;
	if(delegate:Profile().GENERAL.VISIBLE and delegate:Profile().BUFFS.DEBUFFS_VISIBLE) then
		--  Display debuff buttons
		for index = 1,20 do
			name, texture, count = UnitDebuff(delegate.unit, index);
			frame = getglobal(delegate:Profile().BUFFS.DEBUFFS_FRAME.."Buff"..index);
			if(name) then
				if(count < 1) then
					count = "";
				end;
				getglobal(frame:GetName().."Icon"):SetTexture(texture);
				getglobal(frame:GetName().."Count"):SetText(count);
				getglobal(frame:GetName().."Duration"):SetText("");
				frame:Show();
			else
				frame:Hide();
			end;
	
			if(GameTooltip:IsOwned(frame)) then
				GameTooltip:SetUnitDebuff(delegate.unit, index);
			end;
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdatePortrait(delegate)
	if(UnitExists(delegate.unit) and delegate:Profile().GENERAL.VISIBLE and delegate:Profile().PORTRAIT.VISIBLE) then
        getglobal(delegate:Profile().PORTRAIT.FRAME.."Portrait"):SetUnit(delegate.unit, nil, true);
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateRaidTargetIcon(delegate)
	local frame = getglobal(delegate:Profile().GENERAL.FRAME);
	if(frame:IsVisible()) then
		local index = GetRaidTargetIndex(delegate.unit);
		frame = getglobal(delegate:Profile().ICONS.RAIDTARGET_FRAME);
		if(index and index > 0 and index < 9 and delegate:Profile().ICONS.RAIDTARGET_VISIBLE) then
			--frame:SetFile("Interface/Common/RaidTarget");
			local markWidth = 1 / 8;
			local left = (index - 1) * markWidth;
			local right = left + markWidth;

			frame:SetTexCoord(left, right, 0.0, 1.0);
			frame:Show();
		else
			frame:Hide();
		end;
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdatePVPStateIcon(delegate)
	if(UnitPKState(delegate.unit) and delegate:Profile().ICONS.PVPSTATE_VISIBLE) then
		getglobal(delegate:Profile().ICONS.PVPSTATE_FRAME):Show();
	else
		getglobal(delegate:Profile().ICONS.PVPSTATE_FRAME):Hide();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdatePartyLeaderIcon(delegate)
	local isLeader = (GetNumPartyMembers() > 0 and UnitIsUnit("party"..GetPartyLeaderIndex(), delegate.unit)) 
		or (GetNumRaidMembers() > 0 and UnitRaidState(delegate.unit)) 
		or (UnitIsUnit(delegate.unit, "player") and IsPartyLeader());
    if(isLeader and delegate:Profile().ICONS.RAIDLEADER_VISIBLE) then
		getglobal(delegate:Profile().ICONS.RAIDLEADER_FRAME):Show();
	else
		getglobal(delegate:Profile().ICONS.RAIDLEADER_FRAME):Hide();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateLootMasterIcon(delegate)
	local isLooter = UnitIsMasterLooter(delegate.unit) or(UnitIsUnit(delegate.unit, "player") and IsAssigner());
    if(isLooter and delegate:Profile().ICONS.LOOTMASTER_VISIBLE) then
		getglobal(delegate:Profile().ICONS.LOOTMASTER_FRAME):Show();
	else
		getglobal(delegate:Profile().ICONS.LOOTMASTER_FRAME):Hide();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateBossIcon(delegate)
	local frame = getglobal(delegate:Profile().ICONS.BOSS_FRAME);		
	if(delegate:Profile().ICONS.BOSS_VISIBLE and not UnitIsPlayer(delegate.unit) and UnitSex(delegate.unit) > 1) then
		if UnitSex(delegate.unit) > 2 then
			frame:SetFile("Interface/TargetFrame/TargetFrame-BossIcon");
		else
			frame:SetFile(ikarus.constants.ADDON_DIR.."graphics/icons/eliteicon");
		end;
		frame:Show();
	else
		frame:Hide();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateMainClassIcon(delegate)
	local class, _ = UnitClassToken(delegate.unit);
    if (class ~= "" and delegate:Profile().ICONS.MAINCLASS_VISIBLE) then
		local frame = getglobal(delegate:Profile().ICONS.MAINCLASS_FRAME);
		frame:SetFile("Interface/TargetFrame/targetframeicon-"..class);
		frame:Show();
	else
		getglobal(delegate:Profile().ICONS.MAINCLASS_FRAME):Hide();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:UpdateSubClassIcon(delegate)
	local _, class = UnitClassToken(delegate.unit);
    if (class ~= "" and delegate:Profile().ICONS.SUBCLASS_VISIBLE) then
		local frame = getglobal(delegate:Profile().ICONS.SUBCLASS_FRAME);
		frame:SetFile("Interface/TargetFrame/targetframeicon-"..class);
		frame:Show();
	else
		getglobal(delegate:Profile().ICONS.SUBCLASS_FRAME):Hide();
	end;
end;

--  DUMMY SUPPORT

function ikarus.delegates.BasicUnitDelegateClass:ShowDummyBar(config)
	if(config.VISIBLE) then
		local frame = getglobal(config.FRAME);
		getglobal(config.FRAME.."ForegroundTexture"):SetWidth(math.floor(frame:GetWidth()/2));
		getglobal(config.FRAME.."ForegroundTexture"):SetTexCoord(0,0.5,0,1);
		self:ShowDummyLabel(config, "LEFTTEXT");
		self:ShowDummyLabel(config, "RIGHTTEXT");
		self:ShowDummyLabel(config, "OUTSIDE_LEFTTEXT");
		self:ShowDummyLabel(config, "OUTSIDE_RIGHTTEXT");
		frame:Show();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:ShowDummyLabel(config, prefix)
	if(ikarus.utils:IsValidString(prefix)) then
		prefix = prefix.."_";
	else
		prefix = "";
	end;
	if(config[prefix.."VISIBLE"]) then
		local frame = getglobal(config[prefix.."FRAME"]);
		frame:SetText("XXXX");
		frame:Show();
	end;
end;


function ikarus.delegates.BasicUnitDelegateClass:ShowDummyFrame(config, prefix)
	if(ikarus.utils:IsValidString(prefix)) then
		prefix = prefix.."_";
	else
		prefix = "";
	end;
	if(config[prefix.."VISIBLE"]) then
		getglobal(config[prefix.."FRAME"]):Show();
	end;
end;

function ikarus.delegates.BasicUnitDelegateClass:ShowDummyBuffs(config, prefix, idx)
	if(ikarus.utils:IsValidString(prefix)) then
		prefix = prefix.."_";
	else
		prefix = "";
	end;
	if(config[prefix.."VISIBLE"]) then
		local frame, texture = getglobal(config[prefix.."FRAME"]), "Interface/Icons/Christmas_"..idx..".dds";
		frame:Show();
		for index = 1,20 do
			frame = getglobal(config[prefix.."FRAME"].."Buff"..index);
			getglobal(frame:GetName().."Icon"):SetTexture(texture);
			getglobal(frame:GetName().."Count"):SetText("");
			getglobal(frame:GetName().."Duration"):SetText("1.0");
			frame:Show();
		end;
	end;
end;
--  ***********************************************************************


--  ***********************************************************************
--  class handling raid frame behavior
ikarus.delegates.RaidUnitDelegateClass = ikarus:NewClass(ikarus.delegates.BasicUnitDelegateClass);
--  ***********************************************************************

--  ***********************************************************************
--  class handling player cooldown frame behavior
ikarus.delegates.PlayerCoolDownUnitDelegateClass = ikarus:NewClass(ikarus.delegates.BasicUnitDelegateClass);
--  ***********************************************************************

--  ***********************************************************************
--  class handling party cooldown frame behavior
ikarus.delegates.PartyCoolDownUnitDelegateClass = ikarus:NewClass(ikarus.delegates.BasicUnitDelegateClass);
--  ***********************************************************************

--  ***********************************************************************
--  class handling focus frame behavior
ikarus.delegates.FocusUnitDelegateClass = ikarus:NewClass(ikarus.delegates.BasicUnitDelegateClass);
--  ***********************************************************************

--  ***********************************************************************
--  class handling raid mana frame behavior
ikarus.delegates.RaidManaUnitDelegateClass = ikarus:NewClass(ikarus.delegates.BasicUnitDelegateClass);
--  ***********************************************************************

--  ***********************************************************************
--  class handling focus castbar frame behavior
ikarus.delegates.FocusCastBarUnitDelegateClass = ikarus:NewClass(ikarus.delegates.BasicUnitDelegateClass);
--  ***********************************************************************

--  ***********************************************************************
--  class handling main tank frame behavior
ikarus.delegates.MainTankUnitDelegateClass = ikarus:NewClass(ikarus.delegates.BasicUnitDelegateClass);
--  ***********************************************************************


--[[
     ***********************************************************************
    END UNIT DELEGATES
     ***********************************************************************
]]